/**
 * Copyright 2025 Adobe. All rights reserved.
 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. You may obtain a copy
 * of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
 * OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

import Sinon from 'sinon';
import { isWebKit } from '@spectrum-web-components/shared';
import '@spectrum-web-components/icon/sp-icon.js';
import { Icon } from '@spectrum-web-components/icon';
import '@spectrum-web-components/icons/sp-icons-medium.js';
import {
    elementUpdated,
    expect,
    fixture,
    html,
    waitUntil,
} from '@open-wc/testing';
import { testForLitDevWarnings } from '../../../test/testing-helpers.js';

describe('Icon', () => {
    before(async () => {
        const icons = document.createElement('sp-icons-medium');
        document.body.append(icons);

        await elementUpdated(icons);
    });

    it('loads', async () => {
        const el = await fixture<Icon>(html`
            <sp-icon name="ui:Chevron200"></sp-icon>
        `);

        await elementUpdated(el);
        expect(el).to.not.be.undefined;
        const container = el.shadowRoot
            ? (el.shadowRoot.querySelector('#container') as HTMLDivElement)
            : (el.querySelector('#container') as HTMLDivElement);
        expect(container).to.exist;
        const icon = container.querySelector('svg') as SVGElement;
        expect(icon).to.exist;
        expect(icon.getAttribute('aria-hidden')).to.equal('true');
    });

    testForLitDevWarnings(
        async () =>
            await fixture<Icon>(html`
                <sp-icon
                    label="Image Icon"
                    src=""
                ></sp-icon>
            `)
    );

    it('loads w/ src', async () => {
        const el = await fixture<Icon>(html`
            <sp-icon
                label="Image Icon"
                src=""
            ></sp-icon>
        `);

        await elementUpdated(el);

        await expect(el).to.be.accessible();
    });

    it('loads w/ invalid src, error dispatching', async () => {
        const error = Sinon.spy();
        const el = await fixture<Icon>(html`
            <sp-icon
                label="Image Icon"
                src="invalid-image-src"
                @error=${error}
            ></sp-icon>
        `);

        await elementUpdated(el);

        await expect(el).to.be.accessible();

        // Skipping the test case expectation for webkit because of error event not dispatching bug for the same, https://github.com/microsoft/playwright/issues/22332
        if (!isWebKit()) {
            await waitUntil(() => error.calledOnce, 'The error was thrown.');
        }
    });

    it('loads w/ label', async () => {
        const label = 'Chevron';
        const el = await fixture<Icon>(html`
            <sp-icon name="ui:Chevron200" label=${label}></sp-icon>
        `);

        await elementUpdated(el);
        expect(el).to.not.be.undefined;
        const container = el.shadowRoot
            ? (el.shadowRoot.querySelector('#container') as HTMLDivElement)
            : (el.querySelector('#container') as HTMLDivElement);
        expect(container).to.exist;
        const icon = container.querySelector('svg') as SVGElement;
        expect(icon).to.exist;
        expect(icon.hasAttribute('aria-hidden')).to.be.false;
        expect(icon.getAttribute('aria-label')).to.equal(label);
    });

    it('does not error when name is missing', async () => {
        const el = await fixture<Icon>(html`
            <sp-icon></sp-icon>
        `);

        return elementUpdated(el);
    });

    it('does not error with unknown set', async () => {
        const el = await fixture<Icon>(html`
            <sp-icon name="unknown-icon"></sp-icon>
        `);

        return elementUpdated(el);
    });

    it('does error with unknown icon', async () => {
        const el = document.createElement('sp-icon');
        el.name = 'ui:unknown-icon';
        try {
            document.body.appendChild(el);
            await elementUpdated(el);
            expect('failed').to.not.equal('failed');
        } catch (error) {
            expect(() => {
                throw error;
            }).to.throw();
        }
        el.remove();
    });

    it('does not add multiple SVGs when removed and re-added to DOM', async () => {
        const el = await fixture<Icon>(html`
            <sp-icon name="ui:Chevron200"></sp-icon>
        `);

        await elementUpdated(el);
        expect(el).to.not.be.undefined;

        const parent = el.parentNode as HTMLElement;
        parent.removeChild(el);
        parent.appendChild(el);

        // wait for updates
        await el.updateComplete;

        const count = el.shadowRoot.querySelectorAll('svg').length;
        expect(count).to.equal(1);
    });
});
